import Pyro4
import logging as l
import sys
import threading
import random
import time

l.basicConfig(level=l.DEBUG)
#Pyro4.config.COMMTIMEOUT = 10

class Node(object):
    def __init__(self, thisId, daemon, ns):
        l.debug("Node created")
        self.id = thisId
        self.daemon = daemon
        self.ns = ns
        self.next = None
        self.prev = None
        random.seed()
        self.waitForWork = random.randint(5,10)
        self.workTime = random.randint(5,20) * self.id
        self.ACTIVE = 0
        self.PASIVE = 1
        self.WAITING = 2
        self.state = self.WAITING 
    
        self.BLACK = 0
        self.WHITE = 1
        self.token = self.WHITE
         
    def setPrev(self, node):
        print "Moje id {0}, predchadzajuci bude {1}".format(self.id, node)
        self.prev = node
    
    def setNext(self, node):
        print "Moje id {0}, dalsi bude {1}".format(self.id, node)
        self.next=node
    
    def printStatus(self):
        print "Moje id {0}, dalsi je {1}, prechadzajuci je {2}".format(self.id, self.next, self.prev)

    def logout(self):
        print "Logging out"
#        self.prev.setNext(self.next)
#        self.next.setPrev(self.prev)
#        removed = self.ns.remove(name="node.{0}".format(self.id))
#        print "Removed: ", removed
        self.daemon.unregister(self)
        self.daemon.shutdown()
    
    def getAllNodes(self):
        nodes = dict()
        for nodeName, node_uri in self.ns.list(prefix="node.").items():
            obj = Pyro4.Proxy(node_uri)
            obj._pyroOneway.add("terminate")
            obj._pyroOneway.add("logout")
            nodes[int(nodeName.split(".")[1])] = obj  
        return nodes
    
    def getLowestNodeId(self):
        ids = [int(nodeName.split(".")[1]) for nodeName, node_uri in self.ns.list(prefix="node.").items()]
        return min(ids)
    
    def terminate(self):
        print "Mam sa skoncit"
        self.logout()
    
    def colorToken(self, token):
        print "Prijal som token s farbou: ", token
        print "Moj stav je ", self.state
        #ja som ho vyslal
        if self.id == self.getLowestNodeId() and token == self.WHITE:
            for nodeId, node in self.getAllNodes().iteritems():
                if nodeId != self.id:
                    print "Ukoncujem node: ", nodeId
                    node.terminate()
            self.terminate()
        elif self.id == self.getLowestNodeId() and token == self.BLACK:
            print "Dostal som naspat cierny token, posielam znova biely"
            time.sleep(0.5)
            self.next.colorToken(self.WHITE)
            return

        if token == self.WHITE:          
            if self.state == self.WAITING or self.state == self.ACTIVE:
                token = self.BLACK
            else:
                token = self.WHITE
        print "Posielam token s farbou: ", token
        self.next.colorToken(token)
        
    def run(self):
        def callMethod():
            while True:
                command = raw_input("> ")
                if command == "q":
                    self.logout()
                
        thread=threading.Thread(target=callMethod)
        thread.setDaemon(True)
        thread.start()

    def work(self):
        def callMethod():
            started = time.time()
            print "Waiting for: ", self.waitForWork, " seconds"
            while (started + self.waitForWork > time.time()):
                time.sleep(0.1)
            self.state = self.ACTIVE
            
            print "Starting work"
            startedWorking = time.time()
            while (startedWorking + self.workTime > time.time()):
                print "Remaining time: ", startedWorking + self.workTime - time.time() 
                time.sleep(1)
            self.state = self.PASIVE
            self.token = self.WHITE
            #skoncil som a mam najnizsie ID
            if self.id == self.getLowestNodeId():
                print "Posielam token"
                self.next.colorToken(self.token)
            print "-- Koniec vlakna --"
                
        thread=threading.Thread(target=callMethod)
        thread.setDaemon(True)
        thread.start()


def main():
    thisId = int(sys.argv[1])
    daemon=Pyro4.Daemon()
    ns = Pyro4.locateNS()
    node = Node(thisId, daemon, ns)
    node_uri=daemon.register(node)
    print node_uri
    name = "node."+str(thisId)
    print name
    ns.register(name, node_uri)

    ids = [int(nodeName.split(".")[1]) for nodeName, node_uri in ns.list(prefix="node.").items()]
    print ids
    print thisId
    if len(ids) == 1:
        print "Som prvy, nerobim nic"
        pass
    elif len(ids) == 2:
        ids.remove(thisId)
        #thisId 2, ids [1,]
        if(thisId > ids[0]):
            print "node." + str(ids[0])
            prev = Pyro4.Proxy(ns.lookup("node." + str(ids[0])))
            node.prev = prev
            prev.setNext(node)
            node.next = None
        else:
            node.prev = None
            next = Pyro4.Proxy(ns.lookup("node." + str(ids[0])))
            node.next = next
            next.setPrev(node)
        print "Moje id {0}, predchadzajuci bude {1}, dalsi bude {2}, ".format(thisId, node.prev, node.next)
    else:
        ids.remove(thisId)
        found = False
        for i in range(len(ids)-1):
            print "Ja {0}, aktualny {1}, dalsi {2}".format(thisId, ids[i], ids[i+1])
            if(i != thisId and thisId > ids[i] and thisId < ids[i+1]):
                print "Nasiel sa medzi {0} a {1}".format(ids[i], ids[i+1])
                found = True
                prev = Pyro4.Proxy(ns.lookup("node." + str(ids[i])))
                next = Pyro4.Proxy(ns.lookup("node." + str(ids[i+1])))
                node.prev = prev
                node.next = next
                prev.setNext(node)
                next.setPrev(node)
        if found == False:
            prev = Pyro4.Proxy(ns.lookup("node." + str(ids[-1])))
            next = Pyro4.Proxy(ns.lookup("node." + str(ids[0])))
            node.prev = prev
            node.next = next
            print "Prev: " , node.prev
            print "Next: " , node.next
            prev.setNext(node)
            next.setPrev(node)
        print "Moje id {0}, predchadzajuci bude {1}, dalsi bude {2}, ".format(thisId, node.prev, node.next)            
    
    if node.prev:
        node.prev._pyroOneway.add("colorToken")
    
    if node.next:
        node.next._pyroOneway.add("colorToken")

    #node.run()
    node.work()            
    daemon.requestLoop()
    print "--- THE END ---"

if __name__ == "__main__":
    main()
